#!/bin/sh
LC_ALL=C
#->
#  Name:		power2
#  URL[1]:		http://linuxrules.googlecode.com
#  URL[2]:		http://lifehacks.googlecode.com
VERSION=0.4.1
#  Depends:		None at all, plain shell and base tools
#  Purpose:		Program intended to do something [unspecified]
#  Goal:		A simple configless script to be called by
#				acpid itself instead of that bloated,
#				incomprehensible and similarly effective,
#				laptop-mode.
#  Modified:	Sat Jan 15 2011, 22:55:52
#  Insects:		What species? No bugs known,yet.

#  Feel free to contact me at:
#  <http://sites.google.com/site/code933k>
#  in case of bugs, updates, proposals or comments

#  Copyright (C) 2009 Mario García H.
 
#  "THE BEER-WARE LICENSE" (Revision 42):
#  <code933k (AT) gmail> wrote this file. As long as you retain
#  this notice you can do whatever you want with this stuff.

#  If we meet some day, and you think this stuff is worth it,
#  you can buy me a BEER in return, Mario García H.

#  THIS IS FREE SOFTWARE
#  THERE IS NO WARRANTY, TO THE EXTENT PERMITTED BY LAW.
#<-

PATH=/sbin:/usr/sbin:/bin:/usr/bin
# Power control for USB makes my drives fail miserably
# option [u] enables usb power handling anyway.
USB=false

trap 'echo nep nep! wait a minute' INT TERM HUP KILL
printf "\n\033[01;34mPower2:\033[m  A helper for most system power managers, version $VERSION\n"
set +e

# KIND OF LOG
LOG=/var/log/power2.log
echo "Last issued: $(date)" > "$LOG"
echo "Options used: $*"   >> "$LOG"

error_log() {
    printf "$*"
    echo >> "$LOG"
    echo "Errors:" >> "$LOG"
    echo "$*" >> "$LOG"
}

power2_help() {
printf "HELP\n"

cat <<EOF

A little script to help saving a few Watts out of your laptop
Options have quite similar effects, depending on your rig.

CURRENT FEATURES:
* Unplug extra CPUs on saving modes (kernel HOTPLUG + SMP)
  must be available, of course.
* Shutdown webcams (should work for most models) if messaging
  are in use it shouldn't be turned off.
* Slowdown disks (via hardware and kernel params)
* Try to powersave audio and usb ports by means of suspension.

USAGE:
power2.sh [mode] [brightness level]

MODES:
p|performance		Performance, AC plug
s|powersave|save	Regular powersaving
a|agressive			Agressive powersave
x|e|xtreme|extreme	Extreme powersave
u|usb               Enable USB power handling. This is
                    currently discouraged as many drives
                    appear to fail (bad sense errors, etc).
b|brightness        Change brightness (accepts an integer)
h|help|-h|--help    Shows this screen

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

Copyright (C) 2009 Mario García H. License: beerware rev,42
Read full license: http://gnu.org/licenses/gpl.html

THIS IS FREE SOFTWARE AND IS PROVIDED AS-IS WITH NO
GUARANTEE TO THE EXTENT PERMITTED BY LAW

* * * * * * * * * USE AT YOUR OWN RISK AND RESPONSIBILITY!!

EOF

exit 0
}

# I wrote this for: ATI Technologies Inc SBx00 Azalia (Intel HDA)
# select your card controls if needed.

amixer -q sset 'IEC958' mute nocap &>/dev/null
amixer -q sset 'IEC958 Default PCM' mute nocap &>/dev/null
amixer -q sset 'Beep' mute nocap &>/dev/null

ports_power()
{
	# USB && PCI
	AC97=/sys/module/snd_ac97_codec/parameters/power_save_controller
	if test -f $AC97
	then
		echo Y >/sys/module/snd_ac97_codec/parameters/power_save_controller
		#echo 1 >/sys/module/snd_hda_intel/parameters/power_save
		echo 3 >/sys/module/snd_hda_intel/parameters/power_save
	fi

    if $USB
    then
        echo 1 >/sys/module/usbcore/parameters/autosuspend &>/dev/null
        
        for udv in /sys/bus/usb/devices/*/power/level
        do
               echo auto >$udv
        done
        
        for dev in /sys/bus/usb/devices/*/power/autosuspend
        do
               echo 1 > $dev
        done
    fi
}

watchdog() {
	local WATCHDOG=/proc/sys/kernel/nmi_watchdog
	local switch=0
	test -n "$1" && switch=$1

	if test -f "$WATCHDOG"
	then
		echo $switch > /proc/sys/kernel/nmi_watchdog
	fi
}

video_power() {
    case $1 in
        default ) profile=$1;;
        auto    ) profile=$1;;
        low     ) profile=$1;;
        mid     ) profile=$1;;
        high    ) profile=$1;;
        *       ) profile=auto;;
    esac

    for card in $(echo /sys/class/drm/card[0-3])
    do
        if test -f $card/device/power_method
        then
            echo profile  > $card/device/power_method
            echo $profile > $card/device/power_profile
            echo Video power profile set to $profile
        else
            echo no power methods allowed, check your kenel setup
        fi
    done
}

cpu_hotplug() {
	for cpu in $(echo /sys/devices/system/cpu/cpu[1-7])
	do
		test -w $cpu/online \
		&& echo $1 > $cpu/online 2>/dev/null
	done
}

hdd_slowdown() {
	for hdd in $(ls /dev/[s,h]d[a-z])
	do
		hdparm -q -B$1 $hdd || echo Notice: There is an unmanaged drive

		spindown_delay=$(expr $1 / 2)
		test $spindown_delay -lt 1 && spindown_delay=1
		hdparm -q -S $spindown_delay $hdd >/dev/null 2>&1

		if test $1 -lt 200
		then
			echo 5 > /proc/sys/vm/laptop_mode
		else
			echo 0 > /proc/sys/vm/laptop_mode
		fi
	done

	if test $1 -lt 240
	then
		for shost in /sys/class/scsi_host/host*/link_power_management_policy
		do
			echo min_power > $shost
		done
	else
		for shost in /sys/class/scsi_host/host*/link_power_management_policy
		do
			echo max_performance > $shost
		done
	fi
	
	if test -L /dev/cdrom
	then
		if test $1 -lt 198
		then
			hal-disable-polling --device /dev/cdrom
		else
			hal-disable-polling --enable-polling --device /dev/scd0 
		fi
	fi
}

permission_check() {
	if test $UID != 0
	then
		echo You must have administrator permission for most system tasks.
		echo Please run with sudo or log as root.
		exit 1
	fi
}

brightness_ctrl(){
	local newbr=3
	local BR_CTRL=$(find /sys -wholename "*acpi_video[0-9]/brightness" 2>/dev/null)
	test -z "$1" || newbr=$1
	test -f "$BR_CTRL" || return 1
	echo $newbr > "$BR_CTRL"
	printf " brightness, $newbr."
}


printf "\033[00;32mResult: \033[m"

until test -z "$1"
do
    case $1 in
        u|usb)
            shift
            USB=true
        ;;
        v|video)
        shift
        if test "$1" = 'help' -o "$1" = '-h'
        then
            echo ' usage: power2 v [default|auto|low|mid|high]'
            exit 0
        fi

        video_power "$1"
        ;;
        p|performance)
        shift
        permission_check

        # VARIOUS
        amixer -q sset 'Speaker' unmute
        amixer -q sset 'Master' unmute
            
        if ! lsmod |grep uvcvideo >/dev/null
        then
            modprobe -q uvcvideo
            modprobe -q videodev
            modprobe -q v4l1_compat
        fi

        # VIDEO (If KMS available)
        video_power 'auto'

        #CPU
        cpu_hotplug 1

        # DISKS & MEM USAGE
        echo 500 > /proc/sys/vm/dirty_writeback_centisecs
        hdd_slowdown 254

        printf " Performance OK."
        ;;
        s|save|powersave)
        shift
        permission_check

        # VARIOUS
        watchdog 0
        amixer -q sset 'Speaker' unmute
        ports_power

        # VIDEO (If KMS available)
        video_power 'mid'

        #CPU
        cpu_hotplug 0

        # DISKS
        echo 1500 > /proc/sys/vm/dirty_writeback_centisecs
        hdd_slowdown 90

        printf " Powersave OK."
        ;;
        x|xtreme|e|extreme)
        shift
        permission_check

        # VARIOUS
        watchdog 0
        modprobe -q -r uvcvideo
        modprobe -q -r videodev
        modprobe -q -r v4l1_compat
        amixer -q sset 'Speaker' mute nocap
        # amixer -q sset 'Master' mute nocap
        amixer -q sset 'Front Mic' mute nocap &>/dev/null
        amixer -q sset 'Mic' mute nocap &>/dev/null
        ports_power

        # VIDEO (If KMS available)
        video_power 'low'

        #CPU
        cpu_hotplug 0

        # DISKS
        echo 6000 > /proc/sys/vm/dirty_writeback_centisecs
        hdd_slowdown 1

        printf " Extreme OK."
        ;;
        a|agressive)
        shift
        permission_check

        # VARIOUS
        modprobe -q -r uvcvideo
        modprobe -q -r videodev
        modprobe -q -r v4l1_compat
        watchdog 0
        amixer -q sset 'Speaker' mute nocap &>/dev/null
        ports_power

        # VIDEO (If KMS available)
        video_power 'mid'

        #CPU
        cpu_hotplug 0

        # DISKS
        echo 3000 > /proc/sys/vm/dirty_writeback_centisecs
        hdd_slowdown 50

        printf " Agressive OK."
        ;;
        b|brightness)
        shift
        if echo $1 | egrep "^[0-9]+$" >/dev/null
        then
            brightness_ctrl $1
        else
            error_log " Brightness must be an integer. ERROR"
        fi
        ;;
        h|help|-h|--help )
            power2_help
        ;;
        * ) shift
        ;;
    esac
done

echo
exit 0
